#include "Image.hpp"

void createImage(int width_, int height_, char* data_, string filename) {
	FIBITMAP* img = FreeImage_Allocate(width_, height_, 32);
	char* bits = (char*) FreeImage_GetBits(img);

	// bits filling
	for (int i = 0; i < 4 * width_ * height_;i++) bits[i] = data_[i];

	if (!FreeImage_Save(FIF_PNG, img, "save.png")) 
		cout << "ERROR : while saving image." << endl;
	
};

int GenericImage::loadImageFromFile(string filename) {
	const char* filename_c = filename.c_str();
	FREE_IMAGE_FORMAT freeImageFormat = FIF_UNKNOWN;

	freeImageFormat = FreeImage_GetFileType(filename_c,0);
	if (freeImageFormat == FIF_UNKNOWN) {
		// pas de signature trouve, on regarde l'extension du fichier
		freeImageFormat = FreeImage_GetFIFFromFilename(filename_c);
	};
	FIBITMAP* bitmap_p;

	if (freeImageFormat != FIF_UNKNOWN && FreeImage_FIFSupportsReading(freeImageFormat)) {
		// dernier argument = flag 
		bitmap_p = FreeImage_Load(freeImageFormat, filename_c, 0);
	} else bitmap_p = 0;

	// problème dans le chargement de l'image
	if (bitmap_p == 0) return 0;

	FREE_IMAGE_TYPE imageType = FreeImage_GetImageType(bitmap_p);

	// bit par pixel
	unsigned int bpp = FreeImage_GetBPP(bitmap_p);

	m_width = FreeImage_GetWidth(bitmap_p);
	m_height = FreeImage_GetHeight(bitmap_p);
	unsigned int pitch = FreeImage_GetPitch(bitmap_p);
	//cout << "get width : " << FreeImage_GetWidth(bitmap_p) << " " 
	//	<< " height : " << FreeImage_GetHeight(bitmap_p) <<  " m_width " << m_width <<  endl;

	// il faudra ajouter des tests pour les architectures ne supporter que
	// les textures carrées de taille 2**n
	
	void* bits = (void*) FreeImage_GetBits(bitmap_p);
	//unsigned char* textureData = 0;

	//std::cout << "marker 1" << endl;

	GLenum textureFormat;
	GLenum dataType;
	GLint components;

	if ((imageType == FIT_BITMAP) && ((bpp == 24) or (bpp == 32))) {
		textureFormat = GL_RGBA;
		dataType = GL_UNSIGNED_BYTE;
		components = GL_RGBA;
	
		const int redOffset = 2;
		const int greenOffset = 1;
		const int blueOffset = 0;

		//cout << "DEBUG : freeing imageData memory." << endl;
		if (m_imageData) delete m_imageData;
		m_imageData = new unsigned char[m_width * m_height * 4];

		

		for (unsigned int i = 0; i < m_width * m_height * 4; i++) m_imageData[i] = 0;
		if (bpp == 24) {
			//std::cout << "marker 2" << endl;
			for (unsigned int x = 0; x < m_height; x++) 
				for (unsigned int y = 0; y < m_width; y++) { 
					m_imageData[(x * m_width + y) * 4 + redOffset  ] = ((unsigned char*) bits)[x * pitch + y*3 + 0];
					m_imageData[(x * m_width + y) * 4 + greenOffset] = ((unsigned char*) bits)[x * pitch + y*3 + 1];
					m_imageData[(x * m_width + y) * 4 + blueOffset ] = ((unsigned char*) bits)[x * pitch + y*3 + 2];
					m_imageData[(x * m_width + y) * 4 + 3] = 0;
			};
			//std::cout << "marker 24" << endl;
		} else if (bpp == 32) {
			//std::cout << "marker 3" << endl;
			for (unsigned int x = 0; x < m_height; x++) 
				for (unsigned int y = 0; y < m_width; y++) { 
					// TODO : il faudrait normalement utiliser pitch à la place de m_width
					// pour calculer l'indice dans le tableau bits, pitch étant l'arrondi au mot machine
					// de la largeur (width) de scan du fichier, hors comme en RBGA un pixel prend un mot de 32 bits cela fonctionne
					// pour le moment
					m_imageData[(x * m_width + y) * 4 + redOffset  ] = ((unsigned char*) bits)[(x * m_width + y)*4 + 0];
					m_imageData[(x * m_width + y) * 4 + greenOffset] = ((unsigned char*) bits)[(x * m_width + y)*4 + 1];
					m_imageData[(x * m_width + y) * 4 + blueOffset ] = ((unsigned char*) bits)[(x * m_width + y)*4 + 2];
					m_imageData[(x * m_width + y) * 4 + 3 ] = ((unsigned char*) bits)[(x * m_width + y)*4 + 3];
			};
			//std::cout << "marker 4" << endl;
		};
	} else {
		// le format n'est pas pris en compte, on libère le bitmat et on sort
		std::cout << " ERROR : bits per pixel format or image format currently not supported." << std::endl;
		FreeImage_Unload(bitmap_p);
		return 0;
	}
	
	FreeImage_Unload(bitmap_p);
	return 1;
	// creation de la texture
}


GLuint GenericImage::defineTextureFromImage(int wantedId) {
	//glDeleteTextures(1, &m_linkedTextureId);

	if (wantedId < 0) glGenTextures(1, &m_linkedTextureId);
	else m_linkedTextureId = wantedId;

	glBindTexture(GL_TEXTURE_2D, m_linkedTextureId);

	/*glTexImage2D(GL_TEXTURE_2D, 
							 0, 
					   GL_RGBA, 
					   m_width, 
					  m_height, 
							 0, 
					   GL_RGBA,
			  GL_UNSIGNED_BYTE,
				   m_imageData);*/

	// setting parameter for texture
    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

	//cout << "debug : DTFI marqueur 2." << endl;
	GLint alignment;
    //glGetIntegerv (GL_UNPACK_ALIGNMENT, &alignment);
    //glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
	//cout << "debug : DTFI marqueur 3." << endl;

    //gluBuild2DMipmaps (GL_TEXTURE_2D, GL_RGBA,
    //       m_width, m_height,
    //       GL_RGBA, GL_UNSIGNED_BYTE, m_imageData);
	glTexImage2D(GL_TEXTURE_2D, 
							 0, 
					   GL_RGBA, 
					   m_width, 
					  m_height, 
							 0, 
					   GL_RGBA,
			  GL_UNSIGNED_BYTE,
				   m_imageData);
	//cout << "debug : DTFI marqueur 4." << endl;

    //glPixelStorei (GL_UNPACK_ALIGNMENT, alignment);


	return m_linkedTextureId;
}
